﻿using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;

namespace DimensionsHelper.Common.Contracts.Metadata;

/// <summary>
///     MDM文档内的脚本配置。
/// </summary>
public class MetadataScript(string name)
{
    /// <summary>
    ///     脚本配置名。
    /// </summary>
    public string Name { get; } = name;

    /// <summary>
    ///     是否是默认脚本配置。
    /// </summary>
    public bool IsDefault { get; set; }

    /// <summary>
    ///     脚本内容字符串。
    /// </summary>
    public string Script { get; set; } = string.Empty;
}

/// <summary>
///     MDM文档中使用scripttype tag定义的对象。
/// </summary>
public interface IMetadataScriptType : IEnumerable<MetadataScript>
{
    /// <summary>
    ///     当前元数据对象所属的元数据文档。
    /// </summary>
    IMetadataDocument Document { get; }

    /// <summary>
    ///     已删除的脚本对象，XML文档中在 delete 节点中。
    /// </summary>
    IEnumerable<MetadataScript> DeletedScripts { get; }

    /// <summary>
    ///     脚本类型
    /// </summary>
    string Type { get; }

    /// <summary>
    ///     脚本上下文类型
    /// </summary>
    string Context { get; }

    /// <summary>
    ///     访问方式
    /// </summary>
    InterviewModes InterviewModes { get; set; }

    /// <summary>
    ///     使用关键字代码
    /// </summary>
    bool UseKeyCode { get; set; }

    /// <summary>
    ///     脚本类型对象的版本集合。
    /// </summary>
    IVersionObjectCollection? Versions { get; }

    /// <summary>
    ///     创建一个新的<see cref="MetadataScript" />对象并添加进当前列表中。
    /// </summary>
    /// <param name="name">脚本对象名</param>
    MetadataScript AddNew(string name);

    /// <summary>
    ///     向当前集合末尾添加已有对象。
    /// </summary>
    /// <param name="script">已有的脚本对象</param>
    void Add(MetadataScript script);

    /// <summary>
    ///     创建一个新的<see cref="MetadataScript" />对象并添加进已删除对象列表中。
    /// </summary>
    /// <param name="name">脚本对象名</param>
    MetadataScript AddDeletedScript(string name);

    /// <summary>
    ///     向当前删除对象列表的末尾添加已有对象。
    /// </summary>
    /// <param name="script">已有脚本对象</param>
    void AddDeletedScript(MetadataScript script);
}

/// <summary>
///     <see cref="IMetadataScriptType" />类型对象的集合，Tag是scripts
/// </summary>
public interface IMetadataScripts : IEnumerable<IMetadataScriptType>
{
    /// <summary>
    ///     当前元数据对象所属的元数据文档。
    /// </summary>
    IMetadataDocument Document { get; }

    /// <summary>
    ///     已删除的对象集合。
    /// </summary>
    IEnumerable<IMetadataScriptType> DeletedScripts { get; }

    /// <summary>
    ///     脚本类型对象的版本集合。
    /// </summary>
    IVersionObjectCollection? Versions { get; }

    /// <summary>
    ///     创建一个新的<see cref="IMetadataScriptType" />对象并添加进当前列表中。
    /// </summary>
    /// <param name="type">脚本类型</param>
    /// <param name="context">脚本上下文</param>
    IMetadataScriptType AddNew(string type, string context);

    /// <summary>
    ///     向列表末尾添加已有脚本类型对象。
    /// </summary>
    /// <param name="scriptType">已有脚本类型对象</param>
    void Add(IMetadataScriptType scriptType);

    /// <summary>
    ///     创建一个新的<see cref="IMetadataScriptType" />对象并添加进删除对象列表中。
    /// </summary>
    /// <param name="type">脚本类型</param>
    /// <param name="context">脚本上下文</param>
    IMetadataScriptType AddDeletedScriptType(string type, string context);

    /// <summary>
    ///     向当前删除对象列表末尾添加已有对象。
    /// </summary>
    /// <param name="scriptType">已有脚本对象</param>
    void AddDeletedScriptType(IMetadataScriptType scriptType);
}

[Flags]
public enum InterviewModes
{
    Empty = 0,
    Phone = 0x1,
    Web = 0x2,
    Local = 0x4,
    PaperScanning = 0x8,
    PaperManualEntry = 0x10
}

/// <summary>
///     存储路由的变量跳转
/// </summary>
public interface IGoto : IMetadataNamedObject
{
    /// <summary>
    ///     引用的路由元素索引。
    /// </summary>
    int Reference { get; }

    /// <summary>
    ///     跳转配置所在的跳转列表。
    /// </summary>
    IGotoList List { get; }
}

/// <summary>
///     路由跳转配置列表
/// </summary>
public interface IGotoList : IEnumerable<IGoto>
{
    /// <summary>
    ///     跳转列表所在的元素据文档
    /// </summary>
    IMetadataDocument Document { get; }

    /// <summary>
    ///     列表配置数量。
    /// </summary>
    int Count { get; }

    /// <summary>
    ///     跳转配置列表所在的路由单项配置。
    /// </summary>
    IRoutingItem RoutingItem { get; }

    /// <summary>
    ///     向当前集合末尾添加新的跳转配置。
    /// </summary>
    /// <param name="name">配置名</param>
    /// <param name="reference">跳转路由项索引</param>
    IGoto AddNew(string name, int reference);

    /// <summary>
    ///     创建新的跳转配置，不添加进当前集合。
    /// </summary>
    /// <param name="name">配置名</param>
    IGoto CreateObject(string name);

    /// <summary>
    ///     尝试获取给定名称的跳转配置
    /// </summary>
    /// <param name="name">配置名，不区分大小写</param>
    IGoto? Get(string name);

    /// <summary>
    ///     尝试通过配置名获取已有跳转配置。
    /// </summary>
    /// <param name="name">配置名，不区分大小写</param>
    /// <param name="obj">已有的同名配置</param>
    /// <returns>如果存在，返回true，否则，返回false</returns>
    bool TryGet(string name, [MaybeNullWhen(false)] out IGoto obj);
}

/// <summary>
///     MDM文档内使用ritem定义的路由元素。
/// </summary>
public interface IRoutingItem : IMetadataNamedObject
{
    /// <summary>
    ///     此路由元素使用的变量定义。
    /// </summary>
    IVariable? ItemVariable { get; }

    /// <summary>
    ///     此路由元素使用的变量名。
    /// </summary>
    string ItemVariableId { get; }

    /// <summary>
    ///     路由项的跳转配置列表。
    /// </summary>
    IGotoList Goto { get; }
}

/// <summary>
///     <see cref="IRoutingItem" />对象集合。
/// </summary>
public interface IRoutingItems : IMetadataObject, IMetadataStringKeyCollection<IRoutingItem>
{
}

/// <summary>
///     MDM文档路由定义，使用routing tag定义。
/// </summary>
public interface IRouting : IMetadataObject
{
    /// <summary>
    ///     上下文类型
    /// </summary>
    string Context { get; }

    /// <summary>
    ///     访问模式
    /// </summary>
    InterviewModes InterviewModes { get; }

    /// <summary>
    ///     使用关键字代码
    /// </summary>
    bool UseKeyCodes { get; }

    /// <summary>
    ///     路由元素集合
    /// </summary>
    IRoutingItems Items { get; }
}

/// <summary>
///     MDM文档内定义的路由集合，使用routings tag定义。
/// </summary>
public interface IRoutings : INamedObject, IEnumerable<IRouting>
{
    /// <summary>
    ///     路由集合的附加属性集合。
    /// </summary>
    IProperties Properties { get; }

    /// <summary>
    ///     路由使用的脚本代码。
    /// </summary>
    IMetadataScripts Scripts { get; }


    /// <summary>
    ///     上下文对象的版本集合。
    /// </summary>
    IVersionObjectCollection? Versions { get; }

    /// <summary>
    ///     向集合末尾添加一个新的<see cref="IRouting" />对象并返回。
    /// </summary>
    /// <returns></returns>
    IRouting AddNew();
}